<!DOCTYPE html>
<html lang="zh-CN">





<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/myblog/img/apple-touch-icon.png">
  <link rel="icon" type="image/png" href="/myblog/img/favicon.png">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="TakCode Blog">
  <meta name="author" content="谢芃">
  <meta name="keywords" content="">
  <title>Node学习笔记 - TakCode</title>

  <link  rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/5.12.1/css/all.min.css" />
<link  rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/css/bootstrap.min.css" />
<link  rel="stylesheet" href="https://cdn.staticfile.org/mdbootstrap/4.13.0/css/mdb.min.css" />
<link  rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/3.0.1/github-markdown.min.css" />

<link rel="stylesheet" href="//at.alicdn.com/t/font_1067060_qzomjdt8bmp.css">



  <link  rel="stylesheet" href="/myblog/lib/prettify/tomorrow-night-eighties.min.css" />

<link  rel="stylesheet" href="/myblog/css/main.css" />


  <link defer rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css" />


<!-- 自定义样式保持在最底部 -->


<meta name="generator" content="Hexo 4.2.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/myblog/">&nbsp;<strong>TakCode</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/">首页</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/archives/">归档</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/categories/">分类</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/tags/">标签</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/about/">关于</a>
          </li>
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="view intro-2" id="background" parallax=true
         style="background: url('/myblog/img/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask rgba-black-light flex-center">
          <div class="container text-center white-text fadeInUp">
            <span class="h2" id="subtitle">
              
            </span>

            
              
                <p class="mt-3 post-meta">
                  <i class="fas fa-calendar-alt" aria-hidden="true"></i>
                  星期日, 九月 15日 2019, 9:11 晚上
                </p>
              

              <p class="mt-1">
                
                  
                  <span class="post-meta">
                    <i class="far fa-chart-bar"></i>
                    7.9k 字
                  </span>
                

                
                  
                  <span class="post-meta">
                      <i class="far fa-clock"></i>
                      33 分钟
                  </span>
                

                
              </p>
            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="container nopadding-md" id="board-ctn">
        <div class="py-5 z-depth-3" id="board">
          <div class="post-content mx-auto" id="post">
            
            <div class="markdown-body">
              <p>Node学习笔记</p>
<a id="more"></a>
<h3 id="Node是什么"><a href="#Node是什么" class="headerlink" title="Node是什么"></a>Node是什么</h3><p>Node是一个基于 Chrome v8引擎的 JavaScript代码运行环境。</p>
<p>运行环境</p>
<p>浏览器(软件)能够运行JavaScript代码，浏览器就是 JavaScript代码的运行环境</p>
<p>Node(软件)能够运行 JavaScript代码，Node就是 JavaScript代码的运行环境</p>
<h3 id="Node-js运行环境安装"><a href="#Node-js运行环境安装" class="headerlink" title="Node. js运行环境安装"></a>Node. js运行环境安装</h3><p>官网<a href="https://nodejs.org/en/" target="_blank" rel="noopener">https://nodejs.org/en/</a></p>
<ul>
<li>LTS = Long Term Support长期支持版 稳定版</li>
<li>Current拥有最新特性 实验版</li>
</ul>
<p>Node. js的组成</p>
<p>JavaScript由三部分组成， ECMAScript,DOM,BOM。<br>Node.js是由 ECMAScript及Node环境提供的一些附加AP组成的，包括文件、网络、路径等等一些更加强大的APl。</p>
<p><img src="http://helloxx.cn/blogd1.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h3 id="Node-js基础语法"><a href="#Node-js基础语法" class="headerlink" title="Node. js基础语法"></a>Node. js基础语法</h3><p>所有 ECMAScript语法在Node环境中都可以使用。<br>在Node环境下执行代码，使用Node命令执行后缀为js的文件即可</p>
<p>Node. js全局对象 global</p>
<p>在浏览器中全局对象是 window，在Node中全局对象是 global </p>
<p>Node中全局对象下有以下方法，可以在任何地方使用， global可以省略。</p>
<pre><code>console.log()  在控制台中输出

setTimeout()  设置超时定时器

clearTimeout() 清除超时时定时器

setInterval()  设置间歇定时器

clearInterval()  清除间歇定时器</code></pre><h3 id="Node-js模块化开发"><a href="#Node-js模块化开发" class="headerlink" title="Node.js模块化开发"></a>Node.js模块化开发</h3><p>JavaScript开发弊端</p>
<p>JavaScript在使用时存在两大问题，文件依赖和命名冲突</p>
<p>软件中的模块化开发</p>
<p>一个功能就是—个模块，多个模块可以组成完整应用，抽离一个模块不会影响其他功能的运行。</p>
<p><img src="http://helloxx.cn/blogd2.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h4 id="Node-js-中模块化开发规范-commonjs"><a href="#Node-js-中模块化开发规范-commonjs" class="headerlink" title="Node.js 中模块化开发规范(commonjs)"></a>Node.js 中模块化开发规范(commonjs)</h4><p>Node. js规定—个 JavaScript文件就是—个模块，模块内部定义的变量和函数默认情况下在外部无法得到</p>
<p>模块内部可以使用 exports 对象进行成员导岀，使用 require方法导入其他模块</p>
<p><img src="http://helloxx.cn/blogd3.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h4 id="模块成员导出"><a href="#模块成员导出" class="headerlink" title="模块成员导出"></a>模块成员导出</h4><pre><code>// a.js
//在模块内部定义变量
let version = 1.0;
//在模块内部定义方法
const sayHi = name =&gt; &#39;您好,${name}&#39;;
//向模块外部导出数据
exports.version = version;
exports.sayHi = sayHi;</code></pre><h4 id="模块成员的导入"><a href="#模块成员的导入" class="headerlink" title="模块成员的导入"></a>模块成员的导入</h4><pre><code>//b.js
//在b.js模块中导入模块a 
let a = require(&#39;./b.js&#39;);
//输出b模块中的 version变量
console.log(a.version);
//调用b模块中的 sayHi方法并输出其返回值
conso1e.log(a.sayHi(&#39;黑马讲师&#39;));
导入模块时后缀 .js 可以省略</code></pre><h4 id="模块成员导出的另一种方式"><a href="#模块成员导出的另一种方式" class="headerlink" title="模块成员导出的另一种方式"></a>模块成员导出的另一种方式</h4><pre><code>module.exports.version = version;

module.exports.sayHi = sayHi;</code></pre><p>exports 是 module.exports的别名(地址引用关系)，导出对象最终以 module.exports为准</p>
<h4 id="模块导出两种方式的联系与区别"><a href="#模块导出两种方式的联系与区别" class="headerlink" title="模块导出两种方式的联系与区别"></a>模块导出两种方式的联系与区别</h4><p>（最终心module.exports为准）</p>
<p><img src="http://helloxx.cn/blogd4.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h4 id="系统模块"><a href="#系统模块" class="headerlink" title="系统模块"></a>系统模块</h4><p>什么是系统模块</p>
<p>Node运行环境提供的API, 因为这些API都是以模块化的方式进行开发的，所以我们又称Node运行环境提供的API为系统模块</p>
<pre><code class="mermaid">graph TD
A[文件模块 fs]
A --&gt; D[读取文件]
A --&gt; E[写入文件]
A --&gt; F[创建文件夹]</code></pre>
<h4 id="系统模块fs文件操作"><a href="#系统模块fs文件操作" class="headerlink" title="系统模块fs文件操作"></a>系统模块fs文件操作</h4><pre><code class="js">//f:file文件, s:system 系统, 文件操作系统
const fs = require(&#39;fs&#39;);//导入fs模块
//读取文件内容
fs.reaFile(&#39;文件路径/文件名称&#39;[,&#39;文件编码&#39;],callback);//方括号中的为可选参数

//读取上一级Css目录下中的 base.css 
fs.readFile(&#39;./css/base.css&#39;, &#39;utf-8&#39;, (err, doc)=&gt;{
    //如果文件读取发生错误,参数err的值为错误对象,否则err的值为null
    //doc参数为文件内容
    if(err == null){
        //在控制台中输出文件内容
        console.log(doc);
    }
});

//写入文件内容，如果没有这个文件，会自动创建这个文件，如果文件已存在内容，那么会覆盖之前的内容
fs.writeFile(&#39;文件路径/文件名称&#39;,&#39;数据&#39;,callback);//callback为回调函数

const content = &#39;&lt;h3&gt;正在使用fs.writefile写入文件内容&lt;/h3&gt;&#39;;
fs.writeFile(&#39;../index. html&#39;, content, err =&gt;{
    if(err != null){//如果err不为null，则表示文件写入失败
        console.log(err);//打印报错信息
        return;
    }
    console.log(&#39;文件写入成功&#39;);
});

//
fs.appendFile(&#39;文件路径/文件名称&#39;,&#39;追加数据&#39;,callback); 
//上面说的方法都是异步操作，异步操作会返回一个回调函数，在回调函数里面执行结束语句，不然会出现错误

//所有的同步函数，都只是在异步函数后面加上Sync
var res = fs.writeFileSync(&quot;11.txt&quot;,&quot;这里面是使用同步方法写的内容&quot;);
console.log(res);
var data = fs.readFileSync(&quot;11.txt&quot;);
console.log(data.toString());
</code></pre>
<h4 id="系统模块path路径操作"><a href="#系统模块path路径操作" class="headerlink" title="系统模块path路径操作"></a>系统模块path路径操作</h4><p>为什么要进行路径拼接</p>
<ul>
<li>不同操作系统的路径分隔符不统一</li>
<li>/public/uploads/avatar </li>
<li>Windows上是\ /  </li>
<li>Linux上是/</li>
</ul>
<pre><code class="js">//路径拼接语法
path.join(&#39;路径&#39;,&#39;路径&#39;,...)

const path = require(&#39;path&#39;);//导入path模块
let finialPath = path.join(&#39;itcast&#39;, &#39;a&#39;, &#39;b&#39;, &#39;c. css&#39;);//路径拼接
console.log(finialPath);//输出结果itcast\ab\c\c.css</code></pre>
<p>相对路径VS绝对路径</p>
<ul>
<li>大多数情况下使用绝对路径，因为相对路径有时候相对的是命令行工具的当前工作目录</li>
<li>在读取文件或者设置文件路径时都会选择绝对路径</li>
<li>使用__dirname获取当前文件所在的绝对路径</li>
</ul>
<pre><code class="js">var res = fs.writeFileSync(__dirname,&#39;11.txt&#39;,&#39;这里面是使用同步方法写的内容&#39;);</code></pre>
<h4 id="第三方模块"><a href="#第三方模块" class="headerlink" title="第三方模块"></a>第三方模块</h4><p>什么是第三方模块</p>
<p>别人写好的、具有特定功能的、我们能直接使用的模块即第三方模块，由于第三方模块通常都是由多个文件组成并且被放置在一个文件夹中，所以又名 包</p>
<p>第三方模块有两种存在形式：</p>
<ul>
<li>以js文件的形式存在，提供实现项目具体功能的API接口</li>
<li>以命令行工具形式存在，辅助项目开发</li>
</ul>
<h5 id="获取第三方模块"><a href="#获取第三方模块" class="headerlink" title="获取第三方模块"></a>获取第三方模块</h5><p>npmjs.com  第三方模块的存储和分发仓库</p>
<p>npm（ node package manager）：node的第三方模块管理工具</p>
<ul>
<li>下载：npm install 模块名称</li>
<li>卸载：npm unintall package 模块名称</li>
</ul>
<p>全局安装与本地安装</p>
<ul>
<li>命令行工具：全局安装</li>
<li>库文件：本地安装</li>
</ul>
<h5 id="第三方模块-nodemon"><a href="#第三方模块-nodemon" class="headerlink" title="第三方模块 nodemon"></a>第三方模块 nodemon</h5><p>nodemon是一个命令行工具，用以辅助项目开发</p>
<p>在 Node. js中，每次修改文件都要在命令行工具中重新执行该文件，非常繁琐</p>
<p>使用步骤</p>
<p>使用 npm install nodemon -g下载它  , -g全局安装 global</p>
<p>在命令行工具中用 nodemon 命令替代 node 命令执行文件</p>
<h5 id="第三方模块-nrm"><a href="#第三方模块-nrm" class="headerlink" title="第三方模块 nrm"></a>第三方模块 nrm</h5><p>nrm（ npm registry manager）：npm下载地址切换工具</p>
<p>npm默认的下载地址在国外，国内下载速度慢</p>
<p>使用步骤</p>
<p>1.使用 npm install nrm -g 下载它<br>2.查询可用下载地址列表： nrm Is<br>3.切换npm下载地址： nrm use 下载地址名称</p>
<h4 id="第三方模块Gulp"><a href="#第三方模块Gulp" class="headerlink" title="第三方模块Gulp"></a>第三方模块Gulp</h4><p>基于node平台开发的前端构建工具，将机械化操作编写成任务，想要执行机械化操作时执行一个命令行，命令任务就能自动执行了，用机器代替手工，提高开发效率。</p>
<p>Gulp能做什么</p>
<ul>
<li>项目上线，HTML、CSS、JS文件压缩合并</li>
<li>语法转换（es6、less…）</li>
<li>公共文件抽离</li>
<li>修改文件浏览器自动刷新</li>
</ul>
<h5 id="Gulp使用"><a href="#Gulp使用" class="headerlink" title="Gulp使用"></a>Gulp使用</h5><ol>
<li>使用 npm install gulp下载gulp库文件</li>
<li>在项目根目录下建立 gulpfile.js文件</li>
<li>重构项目的文件夹结构src目录放置源代码文件, dist目录放置构建后文件</li>
<li>在 gulpfile.js文件中编写任务</li>
<li>在命令行工具中 gulp-cli 执行gulp任务</li>
</ol>
<h5 id="Gup中提供的方法"><a href="#Gup中提供的方法" class="headerlink" title="Gup中提供的方法"></a>Gup中提供的方法</h5><ul>
<li>gulp.src()：获取任务要处理的文件</li>
<li>gulp.dest()：输出文件</li>
<li>gulp.task()：建立gulp任务</li>
<li>gulp.watch()：监控文件的变化</li>
</ul>
<pre><code class="js">const gulp = require(&#39;gulp&#39;);
//使用 gulp.task()方法建立任务
gulp.task(&#39;first&#39;, () =&gt; {
//获取要处理的文件
gulp.src(&#39;./src/css/base.css&#39;)
//将处理后的文件输出到dist目录
.pipe(gulp.dest(&#39;./dist/css&#39;));
});</code></pre>
<p>需要执行 gulp任务，要使用gulp命令行，需要先安装gulp-cli</p>
<p>npm install gulp-cli -g</p>
<p>然而在命令行中使用 gulp first 命令执行，注意 first为gulp.task() 建立gulp任务的名称</p>
<h5 id="Gulp插件"><a href="#Gulp插件" class="headerlink" title="Gulp插件"></a>Gulp插件</h5><ul>
<li>gulp- htmlmin: htm文件压缩</li>
<li>gulp-csso: 压缩css</li>
<li>gulp- babel: JavaScript语法转化</li>
<li>gulp-less: less语法转化</li>
<li>gulp-uglify: 压缩混淆JavaScript</li>
<li>gulp-file-include 公共文件包含</li>
<li>browsersync 浏览器实时同步</li>
</ul>
<p>Gulp插件的使用</p>
<p> 例如 gulp-htmlmin , 可以在<a href="https://www.npmjs.com/package/gulp-htmlmin" target="_blank" rel="noopener">https://www.npmjs.com/package/gulp-htmlmin</a>  上查看使用方法</p>
<p>npm install gulp-htmlmin</p>
<pre><code class="js">const gulp = require(&#39;gulp&#39;);
const htmlmin = require(&#39;gulp-htmlmin&#39;);

gulp.task(&#39;minify&#39;, () =&gt; {
  gulp.src(&#39;src/*.html&#39;)
    .pipe(htmlmin({ collapseWhitespace: true }))
    .pipe(gulp.dest(&#39;dist&#39;));
});</code></pre>
<h4 id="使用淘宝npm镜像"><a href="#使用淘宝npm镜像" class="headerlink" title="使用淘宝npm镜像"></a>使用淘宝npm镜像</h4><p>npm默认的下载地址在国外，国内下载速度慢，所以使用国内镜像，下载速度快</p>
<pre><code>查看原始npm配置
npm config ls
npm临时使用淘宝镜像安装依赖包
npm i -g express --registry https://registry.npm.taobao.org
也可安装淘宝的cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
查看cnpm版本信息
cnpm -v 
以后安装插件只需要使用cnpm intall即可</code></pre><h4 id="node-modules文件夹的问题"><a href="#node-modules文件夹的问题" class="headerlink" title="node_modules文件夹的问题"></a>node_modules文件夹的问题</h4><ol>
<li>文件夹以及文件过多过碎，当我们将项目整体拷贝给别人的时候，传输速度会很慢很慢。</li>
<li>复杂的模块依赖关系需要被记录，确保模块的版本和当前保持一致，否则会导致当前项目运行报错</li>
</ol>
<h5 id="package-json文件的作用"><a href="#package-json文件的作用" class="headerlink" title="package.json文件的作用"></a>package.json文件的作用</h5><p>项目描述文件，记录了当前项目信息，例如项囯名称版本、作者、 github地址、当前项目依赖了哪些第三方模块等。</p>
<p>使用 npm init -y 命令生成。</p>
<h6 id="项目依赖"><a href="#项目依赖" class="headerlink" title="项目依赖"></a>项目依赖</h6><p>在项目的开发阶段和线上运营阶段，都需要依赖的第三方包，称为项目依赖</p>
<p>使用 npm install 包名命令下载的文件会默认被添加到 package.json文件的 dependencies 字段中</p>
<pre><code class="json">{
    &quot;dependencies&quot;:{
        &quot;jquery&quot;:&quot;^3.3.1&quot;
    }
}</code></pre>
<h6 id="开发依赖"><a href="#开发依赖" class="headerlink" title="开发依赖"></a>开发依赖</h6><p>在项目的开发阶段需要依赖，线上运营阶段不需要依赖的第三方包，称为开发依赖</p>
<p>使用 npm install 包名 –save-dev 命令将包添加到 package.json文件的 devDependencies 字段中</p>
<pre><code class="json">{
    &quot;devDependencies&quot;: {
    &quot;gulp&quot;:&quot;^3.9.1&quot;
    }
}</code></pre>
<p>scripts</p>
<p>当我们需要运行的js命令过长时，就可以把运行的命令放到scripts里，然后使用 npm run 命令名称  来进行运行</p>
<pre><code>&quot;scripts&quot;:{
    &quot;build&quot;:&quot;nodemon app.js&quot;
}
在需要运行时，就在命令行中使用
npm run build</code></pre><h5 id="package-lock-json文件的作用"><a href="#package-lock-json文件的作用" class="headerlink" title="package-lock.json文件的作用"></a>package-lock.json文件的作用</h5><p>锁定包的版本，确保再次下载时不会因为包版本不同而产生问题</p>
<p>加快下载速度，因为该文件中已经记录了项目所依赖第三方包的树状结构和包的下载地址，重新安装时只需下载即可，不需要做额外的工作</p>
<h4 id="Node-js中模块加载机制"><a href="#Node-js中模块加载机制" class="headerlink" title="Node. js中模块加载机制"></a>Node. js中模块加载机制</h4><h5 id="模块查找规则-当模块拥有路径但没有后缀时"><a href="#模块查找规则-当模块拥有路径但没有后缀时" class="headerlink" title="模块查找规则-当模块拥有路径但没有后缀时"></a>模块查找规则-当模块拥有路径但没有后缀时</h5><pre><code>require(&#39;./find.js&#39;);
require(&#39;./find&#39;);</code></pre><ol>
<li>require方法根据模块路径査找模块，如果是完整路径，直接引入模块。</li>
<li>如果模块后缀省略，先找同名JS文件再找同名JS文件夹</li>
<li>如果找到了同名文件夹，找文件夹中的 index.js</li>
<li>如果文件夹中没有 index.js就会去当前文件夹中的 package.json文件中查找main选项中的入口文件</li>
<li>如果找指定的入口文件不存在或者没有指定入口文件就会报错，模块没有被找到 </li>
</ol>
<h5 id="模块查找规则-当模块没有路径且没有后缀时"><a href="#模块查找规则-当模块没有路径且没有后缀时" class="headerlink" title="模块查找规则-当模块没有路径且没有后缀时"></a>模块查找规则-当模块没有路径且没有后缀时</h5><pre><code>require(&#39;find&#39;);</code></pre><ol>
<li>Node.js会假设它是系统模块</li>
<li>Node.js会去 node_modules文件夹中</li>
<li>首先看是否有该名字的JS文件</li>
<li>再看是否有该名字的文件夹</li>
<li>如果是文件夹看里面是否有 index.js</li>
<li>如果没有 index.js査查看该文件夹中的 package.json中的 main选项确定模块入口文件</li>
<li>否则找不到报错</li>
</ol>
<h3 id="创建web服务器"><a href="#创建web服务器" class="headerlink" title="创建web服务器"></a>创建web服务器</h3><pre><code class="js"> // 引用系统模块
 const http = require(&#39;http&#39;);
  // 创建web服务器
 const app = http.createServer();
  // 当客户端发送请求的时候
 app.on(&#39;request&#39;, (req, res) =&gt; {
        //  响应
       res.end(&#39;&lt;h1&gt;hi, user&lt;/h1&gt;&#39;);
 });
  // 监听3000端口
 app.listen(3000);
 console.log(&#39;服务器已启动，监听3000端口，请访问 localhost:3000&#39;)
</code></pre>
<h3 id="HTTP协议"><a href="#HTTP协议" class="headerlink" title="HTTP协议"></a>HTTP协议</h3><h4 id="HTTP协议的概念"><a href="#HTTP协议的概念" class="headerlink" title="HTTP协议的概念"></a>HTTP协议的概念</h4><p>超文本传输协议（英文：HyperText Transfer Protocol，缩写：HTTP）规定了如何从网站服</p>
<p>务器传输超文本到本地浏览器，它基于客户端服务器架构工作，是客户端（用户）和服务器端（网站）请求和应答的标准。</p>
<h4 id="报文"><a href="#报文" class="headerlink" title="报文"></a>报文</h4><p>在HTTP请求和响应的过程中传递的数据块就叫报文，包括要传送的数据和一些附加信息，并且要遵守规定好的格式。</p>
<p><img src="http://helloxx.cn/blogd5.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h5 id="请求报文"><a href="#请求报文" class="headerlink" title="请求报文"></a>请求报文</h5><p>请求方式（ Request method）</p>
<ul>
<li>GET请求数据</li>
<li>POST发送数据</li>
</ul>
<p>请求地址 （Request URL）</p>
<pre><code class="js">app.on(&#39;request&#39;, (req, res) =&gt; {
     console.log(req.headers);  // 获取请求报文
     req.url      // 获取请求地址
     req.method   // 获取请求方法
 });
</code></pre>
<h5 id="响应报文"><a href="#响应报文" class="headerlink" title="响应报文"></a>响应报文</h5><p> HTTP状态码</p>
<ul>
<li>200 请求成功</li>
<li>404 请求的资源没有被找到</li>
<li>500 服务器端错误</li>
<li>400 客户端请求有语法错误</li>
</ul>
<p>内容类型</p>
<ul>
<li>text/html</li>
<li>text/css</li>
<li>application/javascript</li>
<li>image/jpeg</li>
<li>application/json</li>
</ul>
<pre><code class="js">app.on(&#39;request&#39;, (req, res) =&gt; {
    // 设置响应报文
    res.writeHead(200, {
        &#39;Content-Type&#39;: &#39;text/html;charset=utf8‘
    });
});</code></pre>
<h3 id="HTTP请求与响应处理"><a href="#HTTP请求与响应处理" class="headerlink" title="HTTP请求与响应处理"></a>HTTP请求与响应处理</h3><p>请求参数</p>
<p>客户端向服务器端发送请求时，有时需要携带一些客户信息，客户信息需要通过请求参数的形式传递到服务器端，比如登录操作。</p>
<h4 id="GET请求参数"><a href="#GET请求参数" class="headerlink" title="GET请求参数"></a>GET请求参数</h4><ul>
<li>参数被放置在浏览器地址栏中，例如：<a href="http://localhost:3000/?name=zhangsan&amp;age=20" target="_blank" rel="noopener">http://localhost:3000/?name=zhangsan&amp;age=20</a></li>
<li>参数获取需要借助系统模块url，url模块用来处理url地址</li>
</ul>
<pre><code class="js">const http = require(&#39;http&#39;);
// 导入url系统模块 用于处理url地址
const url = require(&#39;url&#39;);
const app = http.createServer();
app.on(&#39;request&#39;, (req, res) =&gt; {
    // 将url路径的各个部分解析出来并返回对象
    // true 代表将参数解析为对象格式
    let {query} = url.parse(req.url, true);
    console.log(query);
});
app.listen(3000);</code></pre>
<h4 id="POST请求参数"><a href="#POST请求参数" class="headerlink" title="POST请求参数"></a>POST请求参数</h4><ul>
<li>参数被放置在请求体中进行传输</li>
<li>获取POST参数需要使用data事件和end事件</li>
<li>使用querystring系统模块将参数转换为对象格式</li>
</ul>
<pre><code class="js">// 导入系统模块querystring 用于将HTTP参数转换为对象格式
const querystring = require(&#39;querystring&#39;);
app.on(&#39;request&#39;, (req, res) =&gt; {
    // 数据格式
    console.log(&#39;content-type: &#39;, req.headers[&#39;content-type&#39;])
    let postData = &#39;&#39;
    // 监听参数传输事件
    req.on(&#39;data&#39;, (chunk) =&gt; postData += chunk);
    // 监听参数传输完毕事件
    req.on(&#39;end&#39;, () =&gt; { 
        console.log(querystring.parse(postData)); //把字符串转换为对象
    }); 
});
</code></pre>
<h4 id="路由"><a href="#路由" class="headerlink" title="路由"></a>路由</h4><p><a href="http://localhost:3000/index" target="_blank" rel="noopener">http://localhost:3000/index</a><br><a href="http://localhost:3000/login" target="_blank" rel="noopener">http://localhost:3000/login</a><br>路由是指客户端请求地址与服务器端程序代码的对应关系。简单的说，就是请求什么响应什么。</p>
<p><img src="http://helloxx.cn/blogd6.png" srcset="/myblog/img/loading.gif" alt=""></p>
<pre><code class="js">// 当客户端发来请求的时候
app.on(&#39;request&#39;, (req, res) =&gt; {
    // 获取客户端的请求路径
    let { pathname } = url.parse(req.url);
    //获取请求方式
    const method = req.method.toLowerCase();
    if (method == &#39;get&#39;){
        if (pathname == &#39;/&#39; || pathname == &#39;/index&#39;) {
            res.end(&#39;欢迎来到首页&#39;);
        } else if (pathname == &#39;/list&#39;) {
            res.end(&#39;欢迎来到列表页页&#39;);
        } else {
            res.end(&#39;抱歉, 您访问的页面出游了&#39;);
        }}else if (method == &#39;post&#39;){}
});</code></pre>
<h4 id="静态资源"><a href="#静态资源" class="headerlink" title="静态资源"></a>静态资源</h4><p>服务器端不需要处理，可以直接响应给客户端的资源就是静态资源，例如CSS、JavaScript、image文件。</p>
<p> <a href="https://www.baidu.com/img/bd_logo1.png" target="_blank" rel="noopener">https://www.baidu.com/img/bd_logo1.png</a> </p>
<pre><code class="js">const http = require(&#39;http&#39;);
const url = require(&#39;url&#39;);
const app = http.createServer();
const fs = require(&#39;fs&#39;);
const path = require(&#39;path&#39;);
const querystring = require(&#39;querystring&#39;);
app.on(&#39;request&#39;, (req, res) =&gt; {
    // 获取用户的请求路径
    let pathname = url.parse(req.url).pathname;
    //将用户的请求路径转换为实际的服务器硬盘路径
    let realPath = path.join(__dirname,&#39;public&#39;+pathname);
    //读取文件
    fs.readFile(realPath,(err,result)=&gt;{
        if (err != null){
            res.end(&#39;not find&#39;)
        }
        res.end(reseult)
    });

});</code></pre>
<h4 id="动态资源"><a href="#动态资源" class="headerlink" title="动态资源"></a>动态资源</h4><p>相同的请求地址不同的响应资源，这种资源就是动态资源。</p>
<p> <a href="http://baijiahao.baidu.com/s?id=1653362293893170887" target="_blank" rel="noopener">http://baijiahao.baidu.com/s?id=1653362293893170887</a> </p>
<p> <strong><code>MIME</code></strong>模块，即：<strong>Multipurpose Internet Mail Extensions</strong>，多用途互联网邮件扩展类型。其主要用途是设置某种扩展名的文件的响应程序类型，我们可以认为是当指定扩展名文件被访问时，浏览器会自动使用指定应用程序来打开。  例如：当服务器要向客户端发送的内容图类为.jpg图片，就需要将<code>Content-Type</code>头设置为<code>image/jpeg</code>，而客户端同样会根据<code>Content-Type</code>对服务器内容进行解析。 </p>
<pre><code class="js">const mime = require(&#39;mime&#39;);
app.on(&#39;request&#39;, (req, res) =&gt; {
    // 获取用户的请求路径
    let pathname = url.parse(req.url).pathname;
    //将用户的请求路径转换为实际的服务器硬盘路径
    let realPath = path.join(__dirname,pathname);
    let type = mime.getType(realPath);//
    console.log(realPath);
    //读取文件
    fs.readFile(realPath,(err,result)=&gt;{
        if (err != null){
            res.writeHead(404,{
                &#39;content-type&#39;:&#39;text/html;charset=utf8&#39;
            })
            res.end(&#39;文件读取失败&#39;);
            return;
        }
        res.writeHead(200, {
            &#39;content-type&#39;:type
        })
        res.end(result)
    });

});
app.listen(3000);</code></pre>
<h4 id="客户端请求途径"><a href="#客户端请求途径" class="headerlink" title="客户端请求途径"></a>客户端请求途径</h4><table>
<thead>
<tr>
<th align="center">GET方式</th>
<th align="center">POST方式</th>
</tr>
</thead>
<tbody><tr>
<td align="center">浏览器地址栏</td>
<td align="center">Form表单提交</td>
</tr>
<tr>
<td align="center">link标签的href属性</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">script标签的src属性</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">img标签的src属性</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">Form表单提交</td>
<td align="center"></td>
</tr>
</tbody></table>
<p><img src="http://helloxx.cn/blogd7.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h3 id="Node-js异步编程"><a href="#Node-js异步编程" class="headerlink" title="Node.js异步编程"></a>Node.js异步编程</h3><h4 id="同步API-异步API"><a href="#同步API-异步API" class="headerlink" title="同步API, 异步API"></a>同步API, 异步API</h4><pre><code class="js">同步API：只有当前API执行完成后，才能继续执行下一个API
console.log(&#39;before&#39;); 
console.log(&#39;after&#39;);
异步API：当前API的执行不会阻塞后续代码的执行
console.log(&#39;before&#39;);
setTimeout(
    () =&gt; { console.log(&#39;last&#39;);
          }, 2000);
console.log(&#39;after&#39;);</code></pre>
<p>同步API, 异步API的区别（ 获取返回值 ）</p>
<pre><code class="js">// 同步
function sum (n1, n2) { 
    return n1 + n2;
} 
const result = sum (10, 20);
// 异步
function getMsg() { 
    setTimeout(function () { 
        return { msg: &#39;Hello Node.js&#39; }
    }, 2000);
}
const msg = getMsg();//undefined
</code></pre>
<p>回调函数</p>
<p>自己定义函数让别人去调用。</p>
<pre><code class="js">// getData函数定义
function getData(callback) {}
// getData函数调用
getData (() =&gt; {});
</code></pre>
<p>使用回调函数获取异步API执行结果</p>
<pre><code class="js">function getMsg(callback) {
    setTimeout(function () {
        callback({ msg: &#39;Hello Node.js&#39; })
    }, 2000);
}
getMsg(function (data) { 
    console.log(data); //Hello Node.js
});
</code></pre>
<p>同步API, 异步API的区别（代码执行顺序）</p>
<pre><code class="js">同步API从上到下依次执行，前面代码会阻塞后面代码的执行
for (var i = 0; i &lt; 100000; i++) { 
    console.log(i);
}
console.log(&#39;for循环后面的代码&#39;);

异步API不会等待API执行完成后再向下执行代码
console.log(&#39;代码开始执行&#39;); //1
setTimeout(() =&gt; { console.log(&#39;2秒后执行的代码&#39;)}, 2000);//4
setTimeout(() =&gt; { console.log(&#39;&quot;0秒&quot;后执行的代码&#39;)}, 0); //3
console.log(&#39;代码结束执行&#39;);//2
</code></pre>
<h4 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h4><p>Promise出现的目的是解决Node.js异步编程中回调地狱的问题。</p>
<pre><code class="js">let promise = new Promise((resolve, reject) =&gt; {//
    setTimeout(() =&gt; {
        if (true) {
            resolve({name: &#39;张三&#39;})
        }else {
            reject(&#39;失败了&#39;) 
        } 
    }, 2000);
});
promise.then(result =&gt; console.log(result); // {name: &#39;张三&#39;})
       .catch(error =&gt; console.log(error); // 失败了)
</code></pre>
<pre><code class="js">//详情请百度云10132939
function p1(){
    return new Promise((resolve, reject)=&gt;{
        fs.readFile(&#39;./1.txt&#39;,&#39;utf8&#39;,(err, result)=&gt;{
            resolve(result)
        })
    });
}
function p2(){
    return new Promise((resolve, reject)=&gt;{
        fs.readFile(&#39;./2.txt&#39;,&#39;utf8&#39;,(err, result)=&gt;{
            resolve(result)
        })
    })
}
function p3(){
    return new Promise((resolve, reject)=&gt;{
        fs.readFile(&#39;./3.txt&#39;,&#39;utf8&#39;,(err, result)=&gt;{
            resolve(result)
        })
    })
}
p1().then((r1)=&gt;{
    console.log(r1);
    return p2();
})
.then((r2)=&gt;{
    console.log(r2);
    return p3();
})
.then((r3)=&gt;{
    console.log(r3);
})</code></pre>
<h4 id="异步函数-es7"><a href="#异步函数-es7" class="headerlink" title="异步函数(es7)"></a>异步函数(es7)</h4><p>异步函数是异步编程语法的终极解决方案，在Promise代码上进行封装，它可以让我们将异步代码写成同步的形式，让代码不再有回调函数嵌套，使代码变得清晰明了。</p>
<p>异步函数就是在普通函数定义的前面加上 async 关键字</p>
<pre><code class="js">const fn = async () =&gt; {};
async function fn(){}
</code></pre>
<h5 id="async关键字"><a href="#async关键字" class="headerlink" title="async关键字"></a>async关键字</h5><ol>
<li>普通函数定义前加async关键字 普通函数变成异步函数</li>
<li>异步函数默认返回promise对象</li>
<li>在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中 return关键字代替了resolve方法</li>
<li>在异步函数内部使用throw关键字抛出程序异常</li>
<li>调用异步函数再链式调用then方法获取异步函数执行结果</li>
<li>调用异步函数再链式调用catch方法获取异步函数执行的错误信息</li>
</ol>
<pre><code class="js">async function fn(){
    return 123;
}
console.log(fn()); //Promise {123}
fn().then(function(data){
    console.log(data); //123
})</code></pre>
<h5 id="await关键字"><a href="#await关键字" class="headerlink" title="await关键字"></a>await关键字</h5><ol>
<li>await关键字只能出现在异步函数中</li>
<li>await promise await后面只能写promise对象,写其他类型的API是不可以的</li>
<li>await关键字可是暂停异步函数向下执行 直到promise返回结果</li>
</ol>
<pre><code class="js">const fs = require(&#39;fs&#39;);
// util下的promisify方法是 改造现有异步函数api让其返回 promise对象从而支持异步函数语法
const promisify = require(&#39;util&#39;).promisify;
//调用 promisify方法改造现有异步API让其返回 promise对象
const readFile = promisify(fs.readFile);
async function run(){
    let r1 = await readFile(&#39;./1. txt&#39;,&#39;utf8&#39;);
    let r2 = await readFile(&#39;./2. txt&#39;,&#39;utf8&#39;);
    let r3 = await readFile(&#39;./3. txt&#39;,&#39;utf8&#39;);
    console.log(r1);
    console.log(r2);
    console.log(r3);
}
run();</code></pre>
<h3 id="MongoDB"><a href="#MongoDB" class="headerlink" title="MongoDB"></a>MongoDB</h3><h4 id="Mongoose第三方包"><a href="#Mongoose第三方包" class="headerlink" title="Mongoose第三方包"></a>Mongoose第三方包</h4><p>使用Node.js操作MongoDB数据库需要依赖Node.js第三方包mongoose<br>使用npm install mongoose命令下载</p>
<p>nodejs  里面关于数据库的操作都是异步操作</p>
<h4 id="启动MongoDB"><a href="#启动MongoDB" class="headerlink" title="启动MongoDB"></a>启动MongoDB</h4><p>在命令行工具中运行net start mongoDB即可启动MongoDB，否则MongoDB将无法连接。</p>
<h4 id="数据库连接"><a href="#数据库连接" class="headerlink" title="数据库连接"></a>数据库连接</h4><p>使用mongoose提供的connect方法即可连接数据库。端口为27017</p>
<pre><code class="js">const mongoose = require(&#39;mongoose&#39;);
mongoose.connect(&#39;mongodb://localhost/playground&#39;, { useUnifiedTopology: true })
    .then(() =&gt; console.log(&#39;数据库连接成功&#39;))
    .catch(err =&gt; console.log(&#39;数据库连接失败&#39;, err));
</code></pre>
<h4 id="创建数据库"><a href="#创建数据库" class="headerlink" title="创建数据库"></a>创建数据库</h4><p>在MongoDB中不需要显式创建数据库，如果正在使用的数据库不存在，MongoDB会自动创建。</p>
<h4 id="mongoDB数据库导入数据"><a href="#mongoDB数据库导入数据" class="headerlink" title="mongoDB数据库导入数据"></a>mongoDB数据库导入数据</h4><p>mongoimport –d 数据库名称 –c 集合名称 –-file 要导入的数据文件<br>找到mongodb数据库的安装目录，将安装目录下的bin目录放置在环境变量中。</p>
<h3 id="MongoDB增删改查操作"><a href="#MongoDB增删改查操作" class="headerlink" title="MongoDB增删改查操作"></a>MongoDB增删改查操作</h3><h4 id="创建集合-表"><a href="#创建集合-表" class="headerlink" title="创建集合(表)"></a>创建集合(表)</h4><p>创建集合分为两步，一是对对集合设定规则，二是创建集合，创建mongoose.Schema构造函数的实例即可创建集合。创建集合时，要插入数据才能创建成功</p>
<pre><code class="js">// 设定集合规则
const courseSchema = new mongoose.Schema({
    name: String,
    author: String,
    isPublished: Boolean
});
// 创建集合并应用规则
const Course = mongoose.model(&#39;Course&#39;, courseSchema); // &#39;Courses&#39; 为表名时
//表名需要后面有s,不然mongoose会自动添加s,不改表名的前提下，可以使用以下方法
const Course = mongoose.model(&#39;user&#39;, courseSchema,&#39;user&#39;); //user为表名时
</code></pre>
<h5 id="mongoose验证"><a href="#mongoose验证" class="headerlink" title="mongoose验证"></a>mongoose验证</h5><p>在创建集合规则时，可以设置当前字段的验证规则，验证失败就则输入插入失败。</p>
<ul>
<li>required: true 必传字段</li>
<li>minlength：3 字符串最小长度</li>
<li>maxlength: 20 字符串最大长度</li>
<li>min: 2 数值最小为2</li>
<li>max: 100 数值最大为100</li>
<li>enum: [‘html’, ‘css’, ‘javascript’, ‘node.js’] </li>
<li>trim: true 去除字符串两边的空格</li>
<li>validate: 自定义验证器</li>
<li>default: 默认值</li>
</ul>
<p>获取错误信息：error.errors[‘字段名称’].message</p>
<pre><code class="js">const userSchema = new mongoose.Schema({
    name: {
        type:String,
        required:[true,&#39;请传入用户名&#39;], //可以传入提示的错误信息
        minlength:2, //最小长度为2
        maxlength:10,//最大长度为10
        trim:true,//去除空格
    },
    age:{
        type:Number,
        min:[18,&#39;年龄不能小于&#39;],//数值最小为18
        max:100,//数值最大为100

    },
    adddate:{
        type:Date,
        default:Date.now,//默认值
    },
    category:{
        type:String,
        enum: [&#39;html&#39;, &#39;css&#39;, &#39;javascript&#39;, &#39;node.js&#39;],//限制传入的数据
    },
    hobbies:[String],
    email:String,
    password:{
        type:String,
        validate:{ //自定义验证器
            validator:v =&gt; {
                //返回布尔值
                //v 是要验证的值
                return v &amp;&amp; v.length &gt;6
            },
            message:&#39;传入的值长度不符合&#39;
        }
    }
});</code></pre>
<h4 id="创建文档"><a href="#创建文档" class="headerlink" title="创建文档"></a>创建文档</h4><p>创建文档实际上就是向集合中插入数据。<br>分为两步：</p>
<ol>
<li>创建集合实例。</li>
<li>调用实例对象下的save方法将数据保存到数据库中。</li>
</ol>
<pre><code class="js">// 创建集合实例
const course = new Course({
    name: &#39;Node.js course&#39;,
    author: &#39;黑马讲师&#39;,
    tags: [&#39;node&#39;, &#39;backend&#39;],
    isPublished: true
});
// 将数据保存到数据库中
course.save();
</code></pre>
<pre><code class="js">//回调函数方式
Course.create({name: &#39;JavaScript基础&#39;, author: &#39;黑马讲师&#39;, isPublish: true}, (err, doc) =&gt; { 
    //  错误对象
    console.log(err)
    //  当前插入的文档
    console.log(doc)
});
</code></pre>
<pre><code class="js">//Promise方式
Course.create({name: &#39;JavaScript基础&#39;, author: &#39;黑马讲师&#39;, isPublish: true})
    .then(doc =&gt; console.log(doc))
    .catch(err =&gt; console.log(err))
</code></pre>
<pre><code class="js">//获取错误信息对象
Course.create({name: &#39;JavaScript基础&#39;, author: &#39;黑马讲师&#39;, isPublish: true})
    .then(doc =&gt; console.log(doc))
    .catch(error =&gt; {
    const err = error.errors;
    for (var attr in err){
        //将错误信息打印到控制台中
        console.log(err[attr][&#39;message&#39;]);
    }
})</code></pre>
<h4 id="查询文档"><a href="#查询文档" class="headerlink" title="查询文档"></a>查询文档</h4><pre><code class="js">//  根据条件查找文档（条件为空则查找所有文档）,find 返回数组形式
Course.find().then(result =&gt; console.log(result))
// 返回文档集合，数组形式
[{
    _id: 5c0917ed37ec9b03c07cf95f,
    name: &#39;node.js基础&#39;,
    author: &#39;黑马讲师‘
},{
    _id: 5c09dea28acfb814980ff827,
    name: &#39;Javascript&#39;,
    author: &#39;黑马讲师‘
}]</code></pre>
<pre><code class="js">//  根据条件查找文档，findOne只返回一条，并且是对象形式
Course.findOne({name: &#39;node.js基础&#39;}).then(result =&gt; console.log(result))
// 返回文档
{
    _id: 5c0917ed37ec9b03c07cf95f,
    name: &#39;node.js基础&#39;,
    author:&#39;黑马讲师&#39;
}
</code></pre>
<pre><code class="js">//  匹配 大于(gt) 小于(lt)
User.find({age: {$gt: 20, $lt: 50}}).then(result =&gt; console.log(result))//age&gt;20 or age&lt;50

//  匹配包含
User.find({hobbies: {$in: [&#39;敲代码&#39;]}}).then(result =&gt; console.log(result))

//  选择要查询的字段  
User.find().select(&#39;name email&#39;).then(result =&gt; console.log(result))

// 将数据按照年龄进行排序
User.find().sort(&#39;age&#39;).then(result =&gt; console.log(result))//age升序  -age降序

//  skip 跳过多少条数据  limit 限制查询数量
User.find().skip(2).limit(2).then (result =&gt; console.log(result))
</code></pre>
<h4 id="删除文档"><a href="#删除文档" class="headerlink" title="删除文档"></a>删除文档</h4><pre><code class="js">// 删除单个
Course.findOneAndDelete({}).then(result =&gt; console.log(result))

// 删除多个
User.deleteMany({}).then(result =&gt; console.log(result))</code></pre>
<h4 id="更新文档"><a href="#更新文档" class="headerlink" title="更新文档"></a>更新文档</h4><pre><code class="js">// 更新单个
User.updateOne({查询条件}, {要修改的值}).then(result =&gt; console.log(result))

// 更新多个
User.updateMany({查询条件}, {要更改的值}).then(result =&gt; console.log(result))
</code></pre>
<h4 id="集合关联-联合"><a href="#集合关联-联合" class="headerlink" title="集合关联(联合)"></a>集合关联(联合)</h4><p>通常不同集合的数据之间是有关系的，例如文章信息和用户信息存储在不同集合中，但文章是某个用户发表的，要查询文章的所有信息包括发表用户，就需要用到集合关联。</p>
<p>使用id对集合进行关联<br>使用populate方法进行关联集合查询</p>
<p><img src="http://helloxx.cn/blogd8.png" srcset="/myblog/img/loading.gif" alt=""></p>
<p>集合关联实现</p>
<pre><code class="js">// 用户集合
const User = mongoose.model(&#39;User&#39;, new mongoose.Schema({ name: { type: String } })); 
// 文章集合
const Post = mongoose.model(&#39;Post&#39;, new mongoose.Schema({
    title: { type: String },
    // 使用ID将文章集合和作者集合进行关联
    author: { type: mongoose.Schema.Types.ObjectId, ref: &#39;User&#39; }
}));
//联合查询
Post.find()
    .populate(&#39;author&#39;)
    .then((err, result) =&gt; console.log(result));
</code></pre>
<h3 id="Express"><a href="#Express" class="headerlink" title="Express"></a>Express</h3><p>Express 搭建一个 web 应用, <a href="https://www.imooc.com/video/20690" target="_blank" rel="noopener">教程地址</a> </p>
<pre><code class="js">const express = require(&#39;express&#39;);

// 一个express 实例
const app = express();

// 编写一个根路径的响应
app.use((req,res) =&gt;{
    res.json({
        name:&quot;张三&quot;
    })
})

// http://localhost:3000/name/:age
app.get(&#39;/name/:age&#39;, (req,res) =&gt; {
    let {age} = req.params;
    res.json({
        name:&#39;tom&#39;,age
    })
})
// 监听3000端口
app.listen(3000,() =&gt; {
    console.log(&#39;server 启动成功 http://localhost:3000&#39;)
})</code></pre>
<h4 id="Route"><a href="#Route" class="headerlink" title="Route"></a>Route</h4><h5 id="定义路由"><a href="#定义路由" class="headerlink" title="定义路由"></a>定义路由</h5><pre><code class="js">// 通过请求方法类型来定义路由 如 get/post/put/delete
app.get(&#39;/demo&#39;,(req,res)=&gt; {
    res.json({
        message:&#39;hello express route from get demo&#39;
    })
})
app.post(&#39;/demo&#39;,(req,res)=&gt; {
    res.json({
        message:&#39;hello express route from post demo&#39;
    })
})

// 通过uri
app.get(&#39;/user/byname&#39;,(req,res)=&gt; {
    let {name} = req.query; // req.query包含路由中查询字符串参数的属性的对象。如果没有,则它是空的对象
    res.json({
        name
    })
})
app.get(&#39;/user/byid&#39;,(req,res) =&gt; {
    let {id} = req.query; // 
    res.json({
        id
    })
})
// http://localhost:3000/user/byname?name=张三 --&gt; {&quot;name&quot;:&quot;张三&quot;}
// http://localhost:3000/user/byid?id=9527 --&gt; {&quot;id&quot;:&quot;110&quot;}</code></pre>
<h5 id="常见需求"><a href="#常见需求" class="headerlink" title="常见需求"></a>常见需求</h5><pre><code class="js">// 需要定义一个 api/路由，需要满足客户端无论使用什么请求方式（get/post/put...）都可以得到响应
app.all(&#39;/demo&#39;, (req,res)=&gt; {
    res.json({
        message:&#39;demo&#39;,
        method:req.method // req.method 包含对应请求HTTP方法的字符串，如 get post 等
    })
})

// get http://localhost:3000/demo --&gt; {&quot;message&quot;:&quot;demo&quot;,&quot;method&quot;:&quot;GET&quot;}
// delete http://localhost:3000/demo --&gt; {&quot;message&quot;:&quot;demo&quot;,&quot;method&quot;:&quot;DELETE&quot;}

// 无论客户端使用任何的uri，我们的服务都可以响应，场景有日志、404
app.all(&#39;*&#39;, (req,res)=&gt; {
    res.json({
        message:&#39;demo&#39;,
        method:req.method,
        uri:req.path
    })
})
// 使用app.use也可以实现以上需求，但app.use通常是用来做中间件的</code></pre>
<h5 id="路由拆分"><a href="#路由拆分" class="headerlink" title="路由拆分"></a>路由拆分</h5><pre><code class="js">// 如何进行路由拆分，比如创建一个 member.router.js 文件
const express = require(&#39;express&#39;)
const router = express.Router();
router.get(&#39;/list&#39;,(req,res)=&gt; {
    res.json({
        list:[{
            id:001,name:&#39;张三&#39;
        }]
    })
})
module.exports = router; // 暴露该路由

// 再创建一个 sku.router.js 文件
const express = require(&#39;express&#39;)
const router = express.Router();
router.get(&#39;/list&#39;,(req,res)=&gt; {
    res.json({
        list:[{
            id:002,name:&#39;皮鞋&#39;，price:100
        }]
    })
})
module.exports = router; // 暴露该路由</code></pre>
<pre><code class="js">// app.js
const meberRouter = require(&#39;./member.router&#39;)
const skuRouter = require(&#39;./sku.router&#39;)
// 注册路由,因为上面两个路由都带有list,所以需要进行拆分
app.use(meberRouter)
app.use(skuRouter)// 如果这样定义，那只能请求到上面其中一个接口
// get http://localhost:3000/list --&gt; {&quot;id&quot;:1,&quot;name&quot;:&quot;张三&quot;}
app.use(&#39;/member&#39;,meberRouter) 
app.use(&#39;/sku&#39;,skuRouter)  // 这样对路由进行拆分，就都能够访问
// get http://localhost:3000/member/list --&gt; {&quot;id&quot;:1,&quot;name&quot;:&quot;张三&quot;}
// get http://localhost:3000/sku/list --&gt; {&quot;id&quot;:2,&quot;name&quot;:&quot;皮鞋&quot;,&quot;price&quot;:100}</code></pre>
<h4 id="中间件"><a href="#中间件" class="headerlink" title="中间件"></a>中间件</h4><p>中间件就类似于一个可插拔的功能，完整的结构就是一个函数，包含 err, req, res, next</p>
<p>1.处理异常</p>
<p>2.处理业务功能，然后转交控制权 next</p>
<p>3.响应请求，结束响应，可以当作路由的处理函数</p>
<pre><code class="js">function valid_name_middleware(req,res,next) {
    let {name} = req.query
    if(!name || name.length) {
        res.json({
            message:&#39;缺少name参数&#39;
        })
    }else{next()}
}
app.all(&#39;*&#39;, valid_name_middleware)
app.get(&#39;/test&#39;,(req,res) =&gt; {
    res.json({
        massage:&#39;test&#39;
    })
})
// post http://localhost:3001  --&gt; {&quot;message&quot;:&quot;缺少name参数&quot;}
// get http://localhost:3001/test?name=  --&gt; {&quot;message&quot;:&quot;缺少name参数&quot;}
// get http://localhost:3001/test?name=123  --&gt; {&quot;message&quot;:&quot;test&quot;}</code></pre>
<p>中间件使用注意事项：</p>
<p>app级别的使用：注册的时候，一定要在最顶级，使用 app.use 加载进来</p>
<pre><code class="js">function log_middleware(req,res,next){
    console.log(&#39;请求来了。。。&#39;);
    next()
}
app.use(log_middleware)
----------加载一个static的中间件----------
app.use(express.static(&#39;static&#39;,{
    extensions:[&#39;html&#39;,&#39;htm&#39;]
}))</code></pre>
<p>router级别的使用</p>
<pre><code>const router = express.Router(); // 路由对象


module.exports = router;</code></pre><p>异常处理</p>
<h4 id="跨域问题"><a href="#跨域问题" class="headerlink" title="跨域问题"></a>跨域问题</h4><pre><code class="js">app.all(&#39;*&#39;,function(req,res,next){
    res.header(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);
  res.header(&#39;Access-Control-Allow-Headers&#39;, &#39;Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild&#39;);
  res.header(&quot;Access-Control-Allow-Methods&quot;, &quot;PUT,POST,GET,DELETE,OPTIONS&quot;);
  res.header(&quot;X-Powered-By&quot;, &#39; 3.2.1&#39;)
  res.header(&quot;Content-Type&quot;, &quot;application/json;charset=utf-8&quot;);
  next();
})</code></pre>
<h3 id="Koa2"><a href="#Koa2" class="headerlink" title="Koa2"></a>Koa2</h3><h4 id="koa-generator脚手架"><a href="#koa-generator脚手架" class="headerlink" title="koa-generator脚手架"></a>koa-generator脚手架</h4><pre><code>安装
npm install -g koa-generator
创建项目
koa2 -e projectName // -e 代码使用 ejs模板引擎
安装所需模块
cd projectName &amp;&amp; npm install
启动项目
DEBUG=projectName:* npm start
自动重启
npm run dev</code></pre><p>koa中间件</p>
<pre><code class="js">function pv(ctx){
    global.console.log(&#39;pv&#39;,ctx.path)
}
module.exports=function(){
    return async function(ctx,next){
        pv(ctx)
        await next()
    }
}</code></pre>
<h3 id="Nuxt-js"><a href="#Nuxt-js" class="headerlink" title="Nuxt.js"></a>Nuxt.js</h3>
            </div>
            <hr>
            <div>
              <p>
                
                
              </p>
              
                <p class="note note-warning">本博客所有文章除特别声明外，均采用 <a href="https://zh.wikipedia.org/wiki/Wikipedia:CC_BY-SA_3.0%E5%8D%8F%E8%AE%AE%E6%96%87%E6%9C%AC" target="_blank" rel="nofollow noopener noopener">CC BY-SA 3.0协议</a> 。转载请注明出处！</p>
              
              
                <div class="post-prevnext row">
                  <div class="post-prev col-6">
                    
                    
                      <a href="/myblog/2019/11/12/%E7%AE%97%E6%B3%95%E5%85%A5%E9%97%A8/">
                        <i class="fa fa-chevron-left"></i>
                        <span class="hidden-mobile">算法入门</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </div>
                  <div class="post-next col-6">
                    
                    
                      <a href="/myblog/2019/05/05/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E5%B8%B8%E7%94%A8%E7%9F%A5%E8%AF%86%E7%82%B9/">
                        <span class="hidden-mobile">前端面试</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="fa fa-chevron-right"></i>
                      </a>
                    
                  </div>
                </div>
              
            </div>

              
          </div>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc-start"></div>
<div id="toc">
  <p class="h5"><i class="far fa-list-alt"></i>&nbsp;目录</p>
  <div id="tocbot"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    
  </main>

  
    <a class="z-depth-1" id="scroll-top-button" href="#" role="button">
      <i class="fa fa-chevron-up scroll-top-arrow" aria-hidden="true"></i>
    </a>
  

  
    <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
  

  

  

  <footer class="mt-5">
  <div class="text-center py-3">
    <div>
      <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><b>Hexo</b></a>
      <i class="iconfont icon-love"></i>
      <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"> <b>Fluid</b></a>
    </div>
    

    

    
  </div>
</footer>

<!-- SCRIPTS -->
<script  src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js" ></script>
<script  src="https://cdn.staticfile.org/popper.js/1.16.1/umd/popper.min.js" ></script>
<script  src="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/js/bootstrap.min.js" ></script>
<script  src="https://cdn.staticfile.org/mdbootstrap/4.13.0/js/mdb.min.js" ></script>
<script  src="/myblog/js/main.js" ></script>


  <script  src="/myblog/js/lazyload.js" ></script>



  
  <script  src="https://cdn.staticfile.org/tocbot/4.10.0/tocbot.min.js" ></script>
  <script>
    $(document).ready(function () {
      var navHeight = $('#navbar').height();
      var toc = $('#toc');
      var boardCtn = $('#board-ctn');
      var boardTop = boardCtn.offset().top;
      var tocLimMax = 2 * boardTop + boardCtn.height();

      $(window).scroll(function () {
        var tocLimMin = $('#toc-start').offset().top - navHeight;
        var scroH = document.body.scrollTop + document.documentElement.scrollTop;

        if (tocLimMin <= scroH && scroH <= tocLimMax) {
          toc.css({
            'display': 'block',
            'position': 'fixed',
            'top': navHeight,
          });
        } else if (scroH <= tocLimMin) {
          toc.css({
            'position': '',
            'top': '',
          });
        } else if (scroH > tocLimMax) {
          toc.css('display', 'none');
        }
      });
      tocbot.init({
        tocSelector: '#tocbot',
        contentSelector: '.post-content',
        headingSelector: 'h1,h2,h3,h4,h5,h6',
        linkClass: 'tocbot-link',
        activeLinkClass: 'tocbot-active-link',
        listClass: 'tocbot-list',
        isCollapsedClass: 'tocbot-is-collapsed',
        collapsibleClass: 'tocbot-is-collapsible',
        scrollSmooth: true,
        headingsOffset: -boardTop
      });
      if ($('.toc-list-item').length > 0) {
        $('#toc > p').css('visibility', 'visible');
      }
      var offset = boardCtn.css('margin-right')
      $('#toc-ctn').css({
        'right': offset
      })
    });
  </script>





  <script defer src="https://cdn.staticfile.org/clipboard.js/2.0.6/clipboard.min.js" ></script>
  <script  src="/myblog/js/clipboard-use.js" ></script>








<!-- Plugins -->



  <script  src="https://cdn.staticfile.org/prettify/188.0.0/prettify.min.js" ></script>
  <script>
    $(document).ready(function () {
      $('pre').addClass('prettyprint  linenums');
      prettyPrint();
    })
  </script>



  <script  src="https://cdn.staticfile.org/typed.js/2.0.11/typed.min.js" ></script>
  <script>
    var typed = new Typed('#subtitle', {
      strings: [
        '  ',
        "Node学习笔记&nbsp;",
      ],
      cursorChar: "_",
      typeSpeed: 70,
      loop: false,
    });
    typed.stop();
    $(document).ready(function () {
      $(".typed-cursor").addClass("h2");
      typed.start();
    });
  </script>



  <script  src="https://cdn.staticfile.org/anchor-js/4.2.2/anchor.min.js" ></script>
  <script>
    anchors.options = {
      placement: "right",
      visible: "hover",
      
    };
    var el = "h1,h2,h3,h4,h5,h6".split(",");
    var res = [];
    for (item of el) {
      res.push(".markdown-body > " + item)
    }
    anchors.add(res.join(", "))
  </script>



  <script  src="/myblog/js/local-search.js" ></script>
  <script>
    var path = "/myblog/local-search.xml";
    var inputArea = document.querySelector("#local-search-input");
    inputArea.onclick = function () {
      getSearchFile(path);
      this.onclick = null
    }
  </script>



  <script defer src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>
  <script>
    $("#post img:not(.no-zoom img, img[no-zoom])").each(
      function () {
        var element = document.createElement("a");
        $(element).attr("data-fancybox", "images");
        $(element).attr("href", $(this).attr("src"));
        $(this).wrap(element);
      }
    );
  </script>












</body>
</html>
